﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Collections;
/*
 * Project Home : http://code.google.com/p/klsudoku
 * Project Owner: ttylikl@gmail.com Email:ttylikl@qq.com
 * Project Blog : http://www.cnblogs.com/ttylikl
 * All Files of this project is free to use , but you should keep the information above when you copy&use it.
 * Infomation Modify Date: 2009.02.22
 * 
 * */
namespace SudokuPanel
{
    //逻辑模块，装载题目，解题
    [Serializable]
    public class puzzle
    {
        public number[,] m_numbers;
        public enum Status { ZERO,READY,PLAYING,SUCCESS,ERROR};
        public bool validate_set = true;//设置为真，则拒绝填入不可能出现的数字
        public puzzle()
        {
            m_numbers = new number[9, 9];
            for (int i = 0; i < 9; ++i)
            {
                for (int j = 0; j < 9; ++j)
                {
                    Point p = new Point(j + 1, i + 1);
                    m_numbers[j, i] = new number(p, 0);//逐行初始化小数格
                }
            }
        }
        public EventPuzzleChanged puzzleChanged;

        public void Clear()
        {
            for (int y = 0; y < 9; ++y)
            {
                int x;
                for (x = 0; x < 9; ++x)
                {
                    m_numbers[x, y].value = 0;
                }
            }
        }

        public String exportPuzzleCompact()
        {
            return pubfun.deflatePuzzle(exportPuzzle());
        }

        public String exportPuzzle()
        {
            StringBuilder sb=new StringBuilder();
            for (int y = 1; y <= 9; ++y)
            {
                for(int x=1;x<=9;++x)
                {
                    sb.Append(this[x, y]);
                }
                sb.Append("\r\n");
            }
            return sb.ToString().Replace("0",".");
        }
        public String exportPuzzle(bool matrix)
        {
            StringBuilder sb = new StringBuilder();
            for (int y = 1; y <= 9; ++y)
            {
                for (int x = 1; x <= 9; ++x)
                {
                    sb.Append(this[x, y]);
                }
                if(matrix) 
                    sb.Append("\r\n");
            }
            return sb.ToString();
        }

        public bool loadPuzzle(String str)
        {
            return loadPuzzle(str.ToCharArray());
        }

        public bool loadPuzzle(char [] pa)
        {
            Clear();
            int idx=0;
            String str = exportPuzzle();
            foreach(char ch in pa)
            {
                if (ch == '\r' || ch == '\n' || ch == ',' || ch == ';')
                    continue;
                int num = ch - '0';
                if (pubfun.isValidValue(num))
                {
                    int x = idx % 9+1;
                    int y = idx / 9+1;
                    if (y > 9)
                        break;
                    if(this[x,y,num]==pubfun.Flag.none)
                    {
                        loadPuzzle(str.ToCharArray());
                        return false;//导入的题目存在错误！
                    }
                    this[x,y]= num;
                }
                else
                {
                    //non-numeric char means empty!
                    //throw new Exception("can't load wrong puzzle value");
                }
                ++idx;
            }
            return true;
        }

        public number get_number(Point p)
        {
            return get_number(p.X, p.Y);
        }

        public number get_number(int x, int y)
        {
            return m_numbers[x - 1, y - 1];
        }

        public List<number> get_group(Point p)
        {
            List<number> ret = new List<number>();
            iterator[] its = new iterator[] { new iteratorX(m_numbers, p), new iteratorY(m_numbers, p), new iteratorZ(m_numbers, p), };
            foreach (iterator it in its)
            {
                foreach (number num in it)
                {
                    if (num.xy == p) continue;
                    bool exist = false;
                    foreach (number n in ret)
                    {
                        if (n.xy == num.xy)
                        {
                            exist = true;
                            break;
                        }
                    }
                    if (exist) continue;
                    ret.Add(num);
                }
            }
            return ret;
        }

        public Status getPuzzleStatus()
        {
            int cntzero=0;
            foreach(number num in m_numbers)
            {
                if (num.value == 0)
                {
                    ++cntzero;
                    if (num.candidates().Length == 0)
                        return Status.ERROR;
                }
            }
            if (cntzero == 81)
                return Status.ZERO;
            if (cntzero == 0)
            {
                for (int i = 1; i <= 9; ++i)
                {
                    foreach (iterator it in new iterator[] { new iteratorX(m_numbers, new Point(1, i)), new iteratorY(m_numbers, new Point(i, 1)), new iteratorX(m_numbers, pubfun.basepoints[i-1]) })
                    {
                        int[] cnt = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
                        foreach (number num in it)
                        {
                            if (num.value > 0)
                                cnt[num.value - 1]++;
                        }
                        foreach (int c in cnt)
                        {
                            if (c != 1)
                            {
                                Debug.WriteLine("在区块"+pubfun.strIteratorName(it)+"里存在重复数字或空白!");
                                return Status.ERROR;
                            }
                        }
                    }
                }
                return Status.SUCCESS;
            }
            return Status.PLAYING;
        }
        /*
         * 对某个指定的单元格进行以下检查：
         *      检查是否已经存在某数
        */
        public bool checkCell(Point p,int n)
        {
            iteratorX itorx = new iteratorX(m_numbers, p);
            iteratorY itory = new iteratorY(m_numbers, p);
            iteratorZ itorz = new iteratorZ(m_numbers, p);
            foreach(number num in itorx)
            {
                if (num.value == n)
                    return true;
            }
            foreach (number num in itory)
            {
                if (num.value == n)
                    return true;
            }
            foreach (number num in itorz)
            {
                if (num.value == n)
                    return true;
            }
            return false;
        }

        //subcell number 索引器
        public pubfun.Flag this[int x, int y, int cand]//1-9
        {
            get
            {
                return m_numbers[x - 1, y - 1][cand - 1];
            }
            set
            {
                if (validate_set && value != pubfun.Flag.none && m_numbers[x - 1, y - 1][cand - 1] == pubfun.Flag.none)
                {
                    //对于从无变有的情况，如果需要检查，则应该检查group里有没有这个值
                    Point p =new Point(x,y);
                    foreach (iterator it in new iterator[] { new iteratorX(m_numbers, p), new iteratorY(m_numbers, p), new iteratorZ(m_numbers, p), })
                    {
                        foreach (number num in it)
                        {
                            if (num.value == cand)
                                return;
                        }
                    }
                }
                List<int[]> nodes = new List<int[]>();
                if (m_numbers[x - 1, y - 1][cand - 1] != value)
                    nodes.Add(new int[] { 1, x, y, cand });
                m_numbers[x - 1, y - 1][cand - 1] = value;
                if (puzzleChanged != null && nodes.Count > 0)
                    puzzleChanged(nodes);
            }
        }
        public pubfun.Flag this[Point p, int cand]//1-9
        {
            get
            {
                return this[p.X, p.Y, cand];
            }
            set
            {
                this[p.X, p.Y, cand] = value;
            }
        }

        //cell number value 索引器
        public int this[Point p]//1-9
        {
            get
            {
                return this[p.X, p.Y];
            }
            set
            {
                this[p.X, p.Y] = value;
            }
        }
        public int this[int x,int y] //允许索引1-9
        {
            get
            {
                return m_numbers[x-1, y-1].value;
            }
            set
            {
                //Debug.WriteLine("Set<" + x + "," + y + ">=" + value);
                if (validate_set && value!=0 && this[x, y, value ] == pubfun.Flag.none)
                    return;//如果候选数无该数字，不允许设置！
                int oldval = m_numbers[x - 1, y - 1].value;
                if (oldval == value)
                    return ;

                List<int[]> nodes = new List<int[]>();
                nodes.Add(new int[] { 0, x, y, value });

                m_numbers[x-1, y-1].value = value;
                Point p = new Point(x, y);
                iteratorX itorx = new iteratorX(m_numbers, p);
                iteratorY itory = new iteratorY(m_numbers, p);
                iteratorZ itorz = new iteratorZ(m_numbers, p);
                if(value>0)
                {
                    //迭代去除重复数
                    foreach (iterator it in new iterator[] { itorx, itory, itorz })
                    {
                        foreach (number num in it)
                        {
                            if (num[value - 1] != pubfun.Flag.none)
                                nodes.Add(new int[]{1, num.xy.X, num.xy.Y, value});
                            num[value - 1] = pubfun.Flag.none;
                        }
                    }
                }
                else
                {
                    //重新计算本格有效数
                    foreach (iterator it in new iterator[] { itorx, itory, itorz })
                    {
                        foreach (number num in it)
                        {
                            if (num.value != 0)
                            {
                                m_numbers[x - 1, y - 1][num.value - 1] = 0;
                            }
                            else
                            {
                                if (!checkCell(num.xy, oldval))
                                {
                                    nodes.Add(new int[]{1,num.xy.X,num.xy.Y,oldval});
                                    num[oldval - 1] = pubfun.Flag.normal;
                                }
                            }
                        }
                    }

                }
                if (puzzleChanged!=null && nodes.Count > 0)
                    puzzleChanged(nodes);
            }
        }

    }
    [Serializable]
    public class number
    {
        private int num;
        private Point p;
        private pubfun.Flag[] m_subnum = new pubfun.Flag[9];
        public Point xy
        {
            get
            {
                return p;
            }
            set
            {
                if (pubfun.isValidPoint(value))
                {
                    p = value;
                }
                else
                {
                    throw new Exception("invalid Point value to set!");
                }
            }
        }

        public int[] candidates()
        {
            List<int> ret=new List<int>();
            for(int i=1;i<=9;++i)
            {
                if (this[i - 1] == pubfun.Flag.normal)
                {
                    ret.Add(i);
                }
            }
            return ret.ToArray();
        }

        public int value
        {
            get
            {
                //Debug.WriteLine("getvalue[" + p.X + "," + p.Y + "]=" + num);
                return num;
            }
            set
            {
                if (value >= 0 && value < 10)
                {
                    num = value;
                    for (int i = 0; i < 9; ++i)
                    {
                        m_subnum[i] = (num != 0) ? pubfun.Flag.none : pubfun.Flag.normal;
                    }
                }
                else
                {
                    throw new Exception("invalid number value to set!");
                }

            }
        }
        public number(Point p, int v)
        {
            xy = p;
            value = v;
            for(int i=0;i<9;++i)
            {
                m_subnum[i] = (v != 0) ? pubfun.Flag.none : pubfun.Flag.normal;
            }
        }


        public pubfun.Flag this[int idx]//允许索引0-8
        {
            get{
                if (!pubfun.isValidIndex(idx))
                {
                    throw new Exception("invalid index value!");
                }
                return m_subnum[idx];
            }
            set{
                if (!pubfun.isValidIndex(idx))
                {
                    throw new Exception("invalid index value!");
                }
                m_subnum[idx] = value;
            }
        }
    }

    public abstract class iterator : IEnumerable
    {
        /*
         * 注意任意一个抽象接口，都不可以破坏next和last的标识
         * 
         */
        
        public abstract iterator begin();
        public abstract iterator end();
        public abstract iterator next();
        public abstract iterator last();

        //仅在构造时赋值一次
        protected number[,] numbers;
        protected Point p;
        protected Point head;
        protected Point tail;

        private iterator() { }

        public bool isBegin()
        {
            return (p == head);
        }

        public bool isEnd()
        {
            return (p == tail);
        }

        public iterator(number[,] numbers, Point p)
        {
            if (!pubfun.isValidPoint(p))
            {
                throw new Exception("Bad Point value!");
            }
            this.p = p;
            this.numbers = numbers;
        }

        public bool isEqual(iterator itor)
        {
            //if (this.begin().value().xy==itor.begin().value().xy && this.end().value().xy==itor.end().value().xy )
            if(this.head==itor.head && this.tail==itor.tail)
            {
                return true;
            }
            return false;
        }
        public number value()
        {
            return numbers[p.X - 1, p.Y - 1];
        }

        public pubfun.Flag this[int idx,int idx2]
        {
            get
            {
                if (!pubfun.isValidIndex(idx)||!pubfun.isValidIndex(idx2))
                    throw new Exception("Invalid Index Value");
                return this[idx][idx2];
            }
            set
            {
                if (!pubfun.isValidIndex(idx)||!pubfun.isValidIndex(idx2))
                    throw new Exception("Invalid Index Value");
                this[idx][idx2]=value;
            }
        }

        public number this[int idx]
        {
            get 
            {
                if (!pubfun.isValidIndex(idx))
                    throw new Exception("Invalid Index Value");
                Point tp = p;
                iterator it = begin();
                while(0<idx--)
                {
                    it = it.next();
                }
                number num=it.value();
                p = tp;
                return num;
            }
        }

        public bool ContainPoint(Point p)
        {
            return (head.X<=p.X&& head.Y<=p.Y && p.X <= tail.X && p.Y<=tail.Y);
            //iterator itor = begin();
            //Point tp = p;
            //while(true)
            //{
            //    if (itor.value().xy == p)
            //    {
            //        p = tp;
            //        return true;
            //    }
            //    if (itor.isEnd())
            //        break;
            //    itor = itor.next();
            //}
            //p = tp;
            //return false;
        }

        public IEnumerator GetEnumerator()
        {
            iterator itor = begin();
            number num = itor.value();
            yield return num;
            do
            {
                itor = itor.next();
                num = itor.value();
                yield return num;
            }
            while (!itor.isEnd());
        }
    }

    public class iteratorX : iterator //横向迭代器
    {

        public iteratorX(number[,] numbers, Point p) : base(numbers, p) 
        {
            head = p;
            head.X = 1;
            tail = p;
            tail.X = 9;
        }

        public override iterator next()
        {
            if (p.X < 9)
            {
                ++p.X;
            }
            return this;
        }

        public override iterator last()
        {
            if (p.X > 1)
            {
                --p.X;
            }
            return this;
        }

        public override iterator begin()
        {
            iteratorX ret = new iteratorX(numbers, head);
            return ret;
        }

        public override iterator end()
        {
            iteratorX ret = new iteratorX(numbers, tail);
            return ret;
        }

    }


    public class iteratorY : iterator //纵向迭代器
    {

        public iteratorY(number[,] numbers, Point p) : base(numbers, p) 
        {
            head = p;
            head.Y = 1;
            tail = p;
            tail.Y = 9;
        }

        public override iterator next()
        {
            if (p.Y < 9)
            {
                ++p.Y;
            }
            return this;
        }

        public override iterator last()
        {
            if (p.Y > 1)
            {
                --p.Y;
            }
            return this;
        }

        public override iterator begin()
        {
            iteratorY ret = new iteratorY(numbers, head);
            return ret;
        }

        public override iterator end()
        {
            iteratorY ret = new iteratorY(numbers, tail);
            return ret;
        }

    }



    public class iteratorZ : iterator //方格迭代器
    {

        public iteratorZ(number[,] numbers, Point p)
            : base(numbers, p)
        {
            int x = (p.X - 1) / 3; // 0 , 1 , 2
            int y = (p.Y - 1) / 3; // 0 , 1 , 2
            head = pubfun.basepoints[x + y * 3];
            tail = new Point(head.X + 2, head.Y + 2);
        }

        public override iterator next()
        {
            if (isEnd())
                return this;
            ++p.X;
            if (p.X > tail.X)
            {
                p.X = head.X;
                ++p.Y;
            }
            return this;
        }

        public override iterator last()
        {
            if (isBegin())
                return this;
            --p.X;
            if (p.X < head.X)
            {
                p.X = tail.X;
                --p.Y;
            }
            return this;
        }

        public override iterator begin()
        {
            iteratorZ ret = new iteratorZ(numbers, head);
            return ret;
        }

        public override iterator end()
        {
            iteratorZ ret = new iteratorZ(numbers, tail);
            return ret;
       }

    }
}